package futbol.tacticas.concursantes.newTeam;

import static java.lang.Math.PI;
import static java.lang.Math.asin;
import static java.lang.Math.cos;
import static java.lang.Math.floor;
import static java.lang.Math.min;
import static java.lang.Math.round;
import static java.lang.Math.sin;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;

import static futbol.tacticas.concursantes.newTeam.FutbolTools.*;


import futbol.*;
import futbol.tacticas.SituacionJugadores;
import futbol.tacticas.concursantes.*;

/**
 * @author janina
 *
 */
/**
 * @author janina
 *
 */
public class Tecnico {
	
	/* TODO TODO TODO
	 * 
	 * 	Millorar el calcul de trajectoria amb la posicio de la pillota inicial -  Aimar
	 * 
	 */
	
	private static Logger 					log	= Logger.getLogger(Tecnico.class);
	private ArrayList<SituacionJugadores> 	historial;
	private int									historialMax = 0; //Recordem les ultimes 10 rondes.
	private static final int							HISTORIAL_MAXIMO = 1800;
	private static final int							HISTORIAL_MINIMO = 3;
	

	private  SituacionJugadores			ultimaSJ;
	
	private static long									startTimeMark;
	
	private int 									ronda;
	private int 									golesHechos;
	private int 									golesRecibidos;
	private int									rondaDeUltimoGol;
	private int[][] 							contrarioMarcado;
	private int 									esGol		= -1;
	
	private CosaPersona			tactica;
	
	private PelotaAnalista					miPelota 				= new PelotaAnalista(0,0,0,0);
	PelotaAnalista 								bola_anterior 		= new PelotaAnalista(0,0,0,0);
	PelotaAnalista 								bola_prevista 		= new PelotaAnalista(0,0,0,0);
	
	private double								angulo_medido		= 0;
	private double								velocidad_medida	= 0;
	private double								error_velocidad 		= 0;
	private double 							error_angulo 		 	= 0;
	private double								error_prediccion 	= 0;

	private Point2D	.Double					origenTrayectoria 				= new Point2D.Double(0,0);
	private int									correccionesTrayectoria 		= 0;
	private boolean 							nueva_trayectoria				=false;
	private ArrayList<PelotaAnalista> 	trayectoria							= new ArrayList<PelotaAnalista>();;
	private ArrayList<PelotaAnalista>  ultimasPelotas					= new ArrayList<PelotaAnalista>();
	private static final int					MAX_CORRECCIONES		= 3;

	
	private PelotaAnalista					ultimaPelotaTrayectoria = null;
	private PelotaAnalista					primeraPelotaChutable = null;
	
	
	
	
	private Juegaytoma[]			receptoresPrimeraChutable 	= null;
	private Juegaytoma[]			receptoresPaseLargo 				= null;
	private Juegaytoma[] 		mejoresInterceptores 			= null;
	private Juegaytoma[] 	mejoresInterceptoresContrarios	= null;
	private boolean							regateadorEnRonda = false;
	
	
	public Tecnico(CosaPersona tactica) 
	{
		
		this.historialMax= trim(1800,HISTORIAL_MINIMO,HISTORIAL_MAXIMO);
		
		if(historialMax>0)
			historial = new ArrayList<SituacionJugadores>();

		ronda			= -1;
		golesHechos		= 0;
		golesRecibidos	= 0;
		rondaDeUltimoGol= 0;
		
		
		this.tactica	= tactica;
		
		regateadorEnRonda = false;
		
		//Colocamos la bola en el centro del campo y inicializamos trayectoria[];
		posicionDeSaque();
	}
	
	public boolean getRegateadorEnRonda()
	{
		return regateadorEnRonda;
	}
	
	public void setRegateadorEnRonda(boolean nuevo )
	{
		this.regateadorEnRonda = nuevo;
	}
	
	/**
	 * <b>No el feu servir!. Sobretot no crideu aquest metode pq no us funcionará res.</b>
	 * @param sj
	 */
	public void nuevaSituacionJugadores(SituacionJugadores sj)
	{
		ultimaSJ = sj;
		// si l'historial esta activat
		if(historialMax>0)
		{
			// afegim la nova situacio a l'historial
			historial.add(ultimaSJ);
			
			// i ens asegurem que no ocupa mes del compte.
			if(historial.size()>historialMax)
			{
				//historial.remove(0);
			}
		}
		
		regateadorEnRonda = false;
		
		// mantenim la compta del temps.
		ronda++;

		// mantenim la compta de gols.
		this.esGol = esGolEnSistema(ultimaSJ.getBola());
		
		if(esGol()==0){
			log.debug("Gol Nostre");
			this.golesHechos++;
			this.rondaDeUltimoGol = this.ronda;
		}else if(esGol()==1){
			log.debug("Gol Contrari");
			this.golesRecibidos++;
			this.rondaDeUltimoGol = this.ronda;
		}
		
		// calcul anticipacio trajectoria de la pilota
		
		if(esGol()==-1){
			analisisDePilota();
		}else{
			posicionDeSaque();
		}
		
		if(ronda!=0 && ronda-getRondaDeUltimoGol()>1)
			actualizarEspionatje();
	}
	
	// setter que activa/desactiva l'historial
	public void setHistorialMax(int historialMax) {
		
		historialMax = General.control(historialMax,HISTORIAL_MINIMO,HISTORIAL_MAXIMO);
		
		if(this.historialMax==0 && historialMax>0) // activar historial
		{
			historial = new ArrayList<SituacionJugadores>(historialMax);
			
		} else
		if(this.historialMax!=0 && historialMax==0) //desactivar historial
		{
			historial.clear();
			historial = null;
		} else
		if(this.historialMax!=0 && this.historial.size() > historialMax) // canvi de tamany
		{
			
			while(this.historial.size() > historialMax)
				historial.remove(0);
		}
		// recordem el nou valor.
		this.historialMax = historialMax;
	}
	

	// SISTEMA CALCUL DE LA TRAJECTORIA DE LA PILOTA
	private void analisisDePilota(){
	
		calculoAngulyYVelocidad();
		
		this.receptoresPrimeraChutable 	= null;
		this.receptoresPaseLargo 		= null;
		this.mejoresInterceptores 			= null;
		this.mejoresInterceptoresContrarios = null;
		this.primeraPelotaChutable	= null;
		this.contrarioMarcado = null;
		
		
		if(this.nueva_trayectoria){
			
			this.primeraPelotaChutable=FutbolTools.calculTrajectoria(miPelota,this.trayectoria);
			this.ultimaPelotaTrayectoria=this.trayectoria.get(this.trayectoria.size()-1);
			
			
		}else{
	
			this.primeraPelotaChutable=updateTrajectoria(this.trayectoria);
		}
		
	}
	
	private void infoPerCalibrar(PelotaAnalista bola_actual, PelotaAnalista bola_anterior, PelotaAnalista bola_prevista){
		
	
		this.angulo_medido		= FutbolTools.calcAngulo(bola_anterior, bola_actual);
		this.velocidad_medida	= bola_anterior.distance(bola_actual);
		if(Math.round(velocidad_medida)>0){
			velocidad_medida--;
		}
		
		this.error_velocidad 		= Math.abs(velocidad_medida-bola_prevista.velocidad);  // Error permès  err < 1
		this.error_angulo 			= Math.abs(angulo_medido-bola_prevista.angulo);		  // Error permès  err <
		this.error_prediccion 	= bola_actual.distance(bola_prevista.getPoint2D());			  // 
	
	}
	
	private boolean hanChutadoPelota(PelotaAnalista pelota){
		
		//Controlar en funcion de correccionesTrayectoria:
		//error_angulo
		//error_velocidad
		//error_prediccion
		
		double fctor_vel = (21-pelota.velocidad)*4/21;
		if(fctor_vel<1)
			fctor_vel = 1;
		
		if(error_angulo > 0.05*fctor_vel*(correccionesTrayectoria+1)){
			if(error_prediccion>1.1){
				return true;
			}
		}
		
		
		if(error_velocidad>1.5){
			if(error_prediccion>0.6*fctor_vel){
				return true;
			}
		}
		
		
		if(error_prediccion>2*(correccionesTrayectoria+1)){
			return true;
		}
		
		return false;
	}
	
	private boolean haRebotado(){
		if(bola_prevista.getHaRebotado())
			if(error_prediccion < 3) 
				return true;
		return false;
	}
	
	private double trimVelocidadDePelotaChutada(double velocidadMedida, int correcciones){
		int vel = 0;
		
		if(Math.abs(velocidadMedida-(20-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel = (20-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(17-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (17-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(14-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (14-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(11-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (11-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(8-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (8-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(5-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (5-(MAX_CORRECCIONES-correcciones));
		}else if(Math.abs(velocidadMedida-(2-(MAX_CORRECCIONES-correcciones)))<1.6){
			vel =  (2-(MAX_CORRECCIONES-correcciones));
		}
		
		if(vel<0)
			vel=0;
		
		return vel;	
	}
	
	
	private void calculoAngulyYVelocidad()
	{
		
		if(trayectoria.size()>0&&historial.size()>1){
			miPelota.setLocation(historial.get(ronda).getBola());
			bola_anterior = new PelotaAnalista(historial.get(ronda-1).getBola(),null,0);
			bola_prevista = trayectoria.get(0);
			
			infoPerCalibrar(miPelota, bola_anterior, bola_prevista);
			
			
			if(haRebotado()){
				nueva_trayectoria = true;
				origenTrayectoria = miPelota.getCopia();
				correccionesTrayectoria = MAX_CORRECCIONES;
				miPelota.angulo = bola_prevista.angulo;
				miPelota.velocidad = bola_prevista.velocidad;
				ultimasPelotas.clear();
				ultimasPelotas.add(0,miPelota.getCopia());
			}else if(hanChutadoPelota(miPelota)){
				nueva_trayectoria = true;
				origenTrayectoria = bola_anterior.getCopia();
				correccionesTrayectoria = MAX_CORRECCIONES;
				miPelota.angulo = angulo_medido;
				miPelota.velocidad = trimVelocidadDePelotaChutada(velocidad_medida, correccionesTrayectoria);
				ultimasPelotas.clear();
				ultimasPelotas.add(0,miPelota.getCopia());
			}else if(correccionesTrayectoria>0){
				correccionesTrayectoria--;
				
				double y = miPelota.y-origenTrayectoria.y;
				double x = miPelota.x-origenTrayectoria.x;
				
				miPelota.angulo = Math.atan2(y,x);
				miPelota.velocidad = velocidad_medida;
				
				PelotaAnalista pel = null;
				for(int i=0; i< ultimasPelotas.size();i++){
					pel = ultimasPelotas.get(i);
					miPelota.velocidad += pel.velocidad-(ultimasPelotas.size()-i);
				}
				
				miPelota.velocidad = miPelota.velocidad/(ultimasPelotas.size()+1);
				ultimasPelotas.add(MAX_CORRECCIONES-correccionesTrayectoria,miPelota.getCopia());
				
			}else if(error_prediccion>0.5){
				miPelota.angulo = bola_prevista.angulo;
				miPelota.velocidad = bola_prevista.velocidad;
				this.nueva_trayectoria = true;
			}else {
				miPelota.angulo = bola_prevista.angulo;
				miPelota.velocidad = bola_prevista.velocidad;
				this.nueva_trayectoria = false;
			}
		}
		
		//////////////// Comprovar que funciona
		//  log.debug(" velocidad= "+(int)Math.round(miPelota.velocidad)+" \terror_velocidad= "+error_velocidad);
		//  log.debug(" angulo= "+miPelota.angulo+" \terror_angulo= "+error_angulo);
		//  log.debug(" error_prediccion= "+error_prediccion);
		////////////////
	}

	
	private PelotaAnalista updateTrajectoria(ArrayList<PelotaAnalista> trayecto){

		
		if(trayecto.size()>1&&trayecto.get(0).velocidad>0)
			trayecto.remove(0);
		
		if(primeraPelotaChutable!=null){
			if(trayecto.get(0).velocidad<primeraPelotaChutable.velocidad){
				return trayecto.get(0).getCopia();
			}
			
			return primeraPelotaChutable.getCopia();
		}
		
		return null;
		
	}
	
	

	private void posicionDeSaque(){
		
		this.trayectoria.clear();
		this.ultimasPelotas.clear();
		this.miPelota.posicionDeSaque();
		this.bola_anterior.posicionDeSaque();
		this.bola_prevista.posicionDeSaque();
		this.trayectoria.add(0,miPelota.getCopia());
		this.origenTrayectoria=miPelota.getCopia();
		this.ultimaPelotaTrayectoria = new PelotaAnalista(0,0,0,0);
		this.primeraPelotaChutable = new PelotaAnalista(0,0,0,0);
		
		this.angulo_medido		= 0;
		this.velocidad_medida	= 0;
		this.error_velocidad 		= 0;
		this.error_angulo 		 	= 0;
		this.error_prediccion 	= 0;
		this.correccionesTrayectoria = 0;
		
		this.receptoresPrimeraChutable 	= null;
		this.receptoresPaseLargo 		= null;
		this.mejoresInterceptores 			= null;
		this.mejoresInterceptoresContrarios = null;
    }
	
	
	// HELPERS
	private int esGolEnSistema(Point bola)
	{
		
        if (bola.getX()>=160 && bola.getY()>=-30 && bola.getY()<=30) {
        	return 0;
        }
        if (bola.getX()<=-160 && bola.getY()>=-30 && bola.getY()<=30){
        	return 1;
        }
        return -1;
	}
	
	
	/**
	 * Retorna si la pilota <b>"bola"</b> es gol:<ul>
	 * <li> <b>-1</b> si aquesta ronda no ha set gol
	 * <li> <b>0</b> si aquesta ha set gol Nostre
	 * <li> <b>1</b> si aquesta ha set gol Contrari
	 * </ul>
	 * @param bola Pilota a evaluar
	 * @return <li> <b>-1</b> si aquesta ronda no ha set gol
	 * <li> <b>0</b> si aquesta ha set gol Nostre
	 * <li> <b>1</b> si aquesta ha set gol Contrari
	 */
	public static int esGol(Point2D bola)
	{
		
        if (bola.getX()>160 && bola.getY()>-29 && bola.getY()<29) {
        	return 0;
        }
        if (bola.getX()<-160 && bola.getY()>-32 && bola.getY()<32){
        	return 1;
        }
        return -1;
	}
	
	
	/**
	 * Retorna si va ser gol en la ronda <b>"ronda"</b>:
	 * <ul>
	 * <li> <b>-1</b> si aquesta ronda no ha set gol
	 * <li> <b>0</b> si aquesta ha set gol Nostre
	 * <li> <b>1</b> si aquesta ha set gol Contrari
	 * </ul>
	 * @param ronda ronda evaluada
	 * @return <li> <b>-1</b> si aquesta ronda no ha set gol
	 * <li> <b>0</b> si aquesta ha set gol Nostre
	 * <li> <b>1</b> si aquesta ha set gol Contrari
	 */
	public int fueGolEnSistema(int ronda)
	{
		return esGolEnSistema(this.historial.get(ronda).getBola());
	}
	
	
	/**
	 * Retorna:
	 * <ul>
	 * <li> <b>-1</b> si aquesta ronda no ha set gol
	 * <li> <b>0</b> si aquesta ha set gol Nostre
	 * <li> <b>1</b> si aquesta ha set gol Contrari
	 * </ul>
	 * @return
	 */
	private int esGol()
	{
		return this.esGol;
	}

	/**
	 * 	util per mesurar temps d'execució de caxos de codi
	 *
	 */
	public static final void startTimeCount()
	{
		startTimeMark = System.currentTimeMillis();
	}
	
	/**
	 * 	util per mesurar temps d'execució de caxos de codi
	 *
	 */
	public static final void endTimeCount(String about)
	{
		log.info(about + " elapsed time: " + (System.currentTimeMillis() - startTimeMark));
	}
	

	
	
	// GETTERS i SETTERS simples
	public int getHistorialMax() {
		return historialMax;
	}

	
	/**
	 * <b>Feulo servir!.</b>
	 * <p>
	 * Aquest si que es tope util. Crideu getPizarraEntrenador() i us tornará un objecte Graphics2D.
	 * Sobre aquest objecte grafics podeu "pintar" el que volgueu. El que "pinteu" es veurá dibuixat sobre
	 * el terreny de joc. Per exemple podeu pintar "una creu vermella" alla a on voleu fer un passe, etc.
	 * <p>
	 * @return - Objecte Graphics2D per pintar-hi damunt.
	 */
	public Graphics2D getPizarraEntrenador() {
		// no cal
		return tactica.getPizarra();
	}
	
	
	/** 
	 * <b>No l'heu de fer servir.</b>
	 * <p>
	 * <p>Paso de comentarl'ho xD
	 * <p>
	 * @return
	 */

	
	public PelotaAnalista getBola() {
		return miPelota;
	}
	public void setBola(PelotaAnalista bola) {
		this.miPelota = bola;
	}
	
	public Personalitat[] getAlineacion(){
		return tactica.getAlineacion();
	}
	public int getGolesHechos() {
		return golesHechos;
	}
	public void setGolesHechos(int golesHechos) {
		this.golesHechos = golesHechos;
	}
	public int getGolesRecibidos() {
		return golesRecibidos;
	}
	public void setGolesRecibidos(int golesRecibidos) {
		this.golesRecibidos = golesRecibidos;
	}
	public int getRonda() {
		return ronda;
	}
	public void setRonda(int time) {
		this.ronda = time;
	}
	public PelotaAnalista getMiPelota() {
		return miPelota;
	}
	public ArrayList<PelotaAnalista> getTrayectoria() {
		return trayectoria;
	}
	
	/**
	 * Retorna la PelotaAnalista predita per la ronda <b>"rondaFutura"</b>
	 * <p>
	 * @param rondaFutura - ronda per la que vols coneixer la pilota
	 * @return - Pilota prevista.
	 */
	public PelotaAnalista getBolaPrevista(int rondaFutura) {
		int index= rondaFutura-ronda-1;
		
		if(index>(trayectoria.size()-1)){
			index=trayectoria.size()-1;
		}
		if(index<0)
			index=0;
		
		return trayectoria.get(index);
	}
	
	public SituacionJugadores getUltimaSJ() {
		return ultimaSJ;
	}
	
	
	public ArrayList<SituacionJugadores> getHistorial() {
		return historial;
	}

	public PelotaAnalista getUltimaPelotaTrayectoria() {	
		return ultimaPelotaTrayectoria;
	}

	/**
	 * Retorna la CosaPersona a la que pertany el tecnico.
	 * @return CosaPersona corresponent.
	 */
	public CosaPersona getTactica() {
		return tactica;
	}
	
	/**
	 * Retorna, de la trajectoria de miPelota, la primera pilota amb velocitat menor de 15 (chutable).
	 * <p>
	 * @return
	 */
	public PelotaAnalista getPrimeraPelotaChutable() {
		return primeraPelotaChutable;
	}

	/**
	 * Retorna el valor de l'atribut <b>"ronda"</b> de l'ultima en que s'ha marcat gol.
	 * <p>
	 * @return Ultima ronda en que s'ha marcat gol.
	 */
	public int getRondaDeUltimoGol() {
		return rondaDeUltimoGol;
	}
	
	
	/**
	 * Retorna el valor de <b>"num"</b> pero acotat entre <b>"min"</b> i <b>"max"</b>.
	 * <p>
	 * @param num
	 * @param min
	 * @param max
	 * @return Num acotat
	 */
	public static double trim(double num, double min, double max) {
		if (num < min)
			return min;
		if (num > max)
			return max;
		return num;
	}
	
	
	/**
	 * Retorna el valor de <b>"num"</b> pero acotat entre <b>"min"</b> i <b>"max"</b>.
	 * <p>
	 * @param num
	 * @param min
	 * @param max
	 * @return Num acotat
	 */
	public static int trim(int num, int min, int max) {
		if (num < min)
			return min;
		if (num > max)
			return max;
		return num;
	}

	// INFORMACIO JUGADORS CONTRARIS.
	//private int[] velocidades = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };

	private int[] velocidades = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };

	
	
	
	private void actualizarEspionatje() {
		SituacionJugadores anteriorSJ = historial.get(ronda - 1);

		Point[] contrarios = ultimaSJ.getContrario();
		Point[] contrariosAnteriores = anteriorSJ.getContrario();

		int fx = 0, fy = 0, i = 0;
		double velocidad;

		for (i = 0; i < 11; i++)
		{
			fx = Math.abs(contrarios[i].x - contrariosAnteriores[i].x);
			fy = Math.abs(contrarios[i].y - contrariosAnteriores[i].y);

			velocidad = Math.hypot(fx, fy);
			
			//log.info(i + "- " + velocidad + " x:" + fx + " y:"+fy);
			
			if(velocidad>7)
				continue;
			
			velocidad = trim(velocidad, 3, 6);

			if (velocidad > velocidades[i])
				velocidades[i] = (int) Math.round(velocidad);

			//log.info(i + "- " + velocidades[i]);
		}
	}

	/**
	 * Segun el espionaje que se hace, devuelve la velocidad deducida.
	 * 
	 * @return la velocidad del jugador. Si aun no se ha podido saber devuelve 3
	 *         (valor minimo, subestima movimiento).
	 */
	public int getVelocidadJugadorContrario(int jug) {
		return velocidades[jug];
	}

	/**
	 * Segun el espionaje que se hace, devuelve la fuerza deducida.
	 * 
	 * @return la fuerza del jugador. Si aun no se ha podido saber devuelve 7
	 *         (valor maximo, sobreestima fuerza);
	 */
	public int getFuerzaJugadorContrario(int jug) {
		return 10 - velocidades[jug];
	}
	
	
	
	/**
	 * 	Ha quedat DEPRECATED per getMejorAInterceptarPelota(). Aquest ultim és molt més util.
	 * 
	 * getReceptorPrimeraChutable() Devuelve un array de objetos Juegaytoma, ordenados por proximidad ascendente 
	 * a la primera pelota con velocidad<15.
	 * @param excluir Array de Point con los indices de los jugadores que excluyes - si no quieres puede poner NULL
	 * @param soloDelante boolean=true si quieres que busque solo por delante de la pelota. - si no quieres puede poner NULL
	 * @return
	 */
	public Juegaytoma[] getReceptoresPrimeraChutable(int[] excluir, boolean soloDelante){
		
		if(receptoresPrimeraChutable==null){
			
			if(primeraPelotaChutable!=null){
				receptoresPrimeraChutable = ordenDeMasCercanos( ultimaSJ.getMisJugadores(),this.primeraPelotaChutable.getPoint(),excluir,soloDelante);
				return receptoresPrimeraChutable;
			}
		}
		
		
		return receptoresPrimeraChutable;
	}
	
	/** 
	 * Devuelve un array de objetos Juegaytoma, ordenados por proximidad ascendente 
	 * a la ultima pelota de la trayectoria.
	 * @param excluir Array de Point con los indices de los jugadores que excluyes - si no quieres puede poner NULL
	 * @param soloDelante boolean=true si quieres que busque solo por delante de la pelota. - si no quieres puede poner NULL
	 * @return Juegaytoma[] - No puede devolver NULL, si os da NullPointerException 
	 * notificar a Aimar del bugg.
	 */
	public Juegaytoma[] getReceptorDePaseLargo(int[] excluir, boolean soloDelante){
		if(receptoresPaseLargo==null){
		
			receptoresPaseLargo = ordenDeMasCercanos(ultimaSJ.getMisJugadores(),ultimaPelotaTrayectoria.getPoint(),excluir,soloDelante);
		}
		return receptoresPaseLargo;
	}
	
	public static Double getDistanciaCritica(int fuerza) {
		switch (fuerza) {
		case 7:
			return 126.0;
		case 6:
			return 66.0;
		case 5:
			return 15.0;
		default:
			return 0.0;
		}
	}
	/**
	 * Devuelve un array de objetos Juegaytoma, ordenados por proximidad ascendente 
	 * al punto <b>"punto"</b>.
	 * <p>
	 * @param lista - Array con las posiciones de los jugadores.
	 * @param punto - Punto respeto al que quieres medir la distancia con todos los jugadores
	 * @param excluir - Array con los indices de los jugadores a excluir de la respuesta.
	 * @param soloDelante - if true, solo comparara con los jugadores de la <b>"lista"</b> que esten por delante de <b>"punto"</b>
	 * @return Devuelve un array de objetos Juegaytoma, ordenados por proximidad ascendente 
	 * al punto <b>"punto"</b>.
	 */
	public Juegaytoma[] ordenDeMasCercanos(Point[] lista, Point punto, int excluir[], boolean soloDelante){
		Juegaytoma[] jugadores= new Juegaytoma[lista.length];
		
		for (int n=0;n<lista.length;n++){
			if (!FutbolTools.estaEnVector(excluir, n)){
				if (!soloDelante || lista[n].getX()>punto.getX()){					
					jugadores[n]=new Juegaytoma(n,lista[n],0,punto);
				}else{
					jugadores[n]=new Juegaytoma(n,lista[n],0,new Point(999,999));
				}
			}else{
				jugadores[n]=new Juegaytoma(n,lista[n],0,new Point(999,999));
			}
		}
		Arrays.sort(jugadores, new ComparadorDeDistancias());
		
		////////////////////Comprovacion de que funciona
		//  for(int i=0; i<11;i++)
		//  log.debug("jug:"+jugadores[i].indiceJugador+" dist:"+jugadores[i].distancia);
		/////////////////////////////////////////////////////////////////////////////////////////
		
		return jugadores;
	}
	
	
	/**
	 * Devuelve un array de objetos Juegaytoma, ordenados segun los turnos que tardaran en cortar la trayectoria
	 * , siempre que la trayectoria sea cortable claro.
	 * 
	 * 
	 * @param alineacion - array de personalitats que te l'entrenador.
	 * @param trayectoria
	 * @return Juegaytoma[] - No puede devolver NULL. Si lo hace notificanos el bugg.
	 */
	public Juegaytoma[] getMejoresInterceptores(){
		
		Personalitat[] alineacion = this.getAlineacion();
		ArrayList<PelotaAnalista> trayectoria = this.trayectoria;
		
		if(mejoresInterceptores==null){
			mejoresInterceptores = new Juegaytoma[alineacion.length];
			Personalitat personalitatAux = null;
			PelotaAnalista pelotaAInterceptarAux=null;
			int indexPelotaAux = 99;
			
			for(int i=0; i<alineacion.length ; i++){
				personalitatAux = alineacion[i];
				personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad,9));
				pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
				indexPelotaAux = trayectoria.indexOf(pelotaAInterceptarAux);
				
				mejoresInterceptores[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
			}
			
			if(mejoresInterceptores.length>0){
				
				Arrays.sort(mejoresInterceptores, new ComparadorDeIndicesYDistancias());
				
				////////////////////Comprovacion de que funciona
				// for(int i = 0; i<mejoresInterceptores.length;i++)
				// log.debug("MEJOR1: "+mejoresInterceptores[0].indiceJugador+"    MEJOR2: "+mejoresInterceptores[1].indiceJugador);
				////////////////////////////////////
			}
			
		}
		
		return mejoresInterceptores;
	}
	
	public Juegaytoma[] getMejoresInterceptoresContrarios(){
	
		Point[] contrarios = this.ultimaSJ.getContrario();
		ArrayList<PelotaAnalista> trayectoria = this.trayectoria;
		Personalitat[] alineacion;
		
		alineacion = conviertePointsEnPersonalitats(contrarios);
		
		
		if(mejoresInterceptoresContrarios==null){
			mejoresInterceptoresContrarios = new Juegaytoma[alineacion.length];
			Personalitat personalitatAux = null;
			PelotaAnalista pelotaAInterceptarAux=null;
			int indexPelotaAux = 99;
			
			for(int i=0; i<alineacion.length ; i++){
				personalitatAux = alineacion[i];
				personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad));
				pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
				indexPelotaAux = trayectoria.indexOf(pelotaAInterceptarAux);
				
				mejoresInterceptoresContrarios[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
			}
			
			if(mejoresInterceptoresContrarios.length>0){
				
				Arrays.sort(mejoresInterceptoresContrarios, new ComparadorDeIndicesYDistancias());
				
				////////////////////Comprovacion de que funciona
				// for(int i = 0; i<mejoresInterceptores.length;i++)
				// log.debug("MEJOR1: "+mejoresInterceptores[0].indiceJugador+"    MEJOR2: "+mejoresInterceptores[1].indiceJugador);
				////////////////////////////////////
			}
			
		}
		
		
		
		return mejoresInterceptoresContrarios;
	}
	
	
	public Juegaytoma[] getMejoresInterceptoresHipotetico(ArrayList<PelotaAnalista> trayectoria, int[] excluir){
		Juegaytoma[] mejoresInterceptores =null;
		Personalitat[] alineacion = this.getAlineacion();
		
		if(mejoresInterceptores==null){
			mejoresInterceptores = new Juegaytoma[alineacion.length];
			Personalitat personalitatAux = null;
			PelotaAnalista pelotaAInterceptarAux=null;
			int indexPelotaAux = 99;
			
			for(int i=0; i<alineacion.length ; i++){
				
				if (!FutbolTools.estaEnVector(excluir, i)){
					personalitatAux = alineacion[i];
					personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad,9));
					pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
					indexPelotaAux = trayectoria.indexOf(pelotaAInterceptarAux);
					
					mejoresInterceptores[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
				}else{
					personalitatAux = alineacion[i];
					personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad,9));
					pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
					indexPelotaAux = 999;
					mejoresInterceptores[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
				}
			}
			
			if(mejoresInterceptores.length>0){
				
				Arrays.sort(mejoresInterceptores, new ComparadorDeIndicesYDistancias());
				
				////////////////////Comprovacion de que funciona
				// for(int i = 0; i<mejoresInterceptores.length;i++)
				// log.debug("MEJOR1: "+mejoresInterceptores[0].indiceJugador+"    MEJOR2: "+mejoresInterceptores[1].indiceJugador);
				////////////////////////////////////
			}
			
		}
		
		return mejoresInterceptores;
	}
	
	public Juegaytoma[] getMejoresInterceptoresContrariosHipotetico(ArrayList<PelotaAnalista> trayectoria, int[] excluir){
		Juegaytoma[] mejoresInterceptoresContrarios =null;
		Point[] contrarios = this.ultimaSJ.getContrario();
		Personalitat[] alineacion;
		
		alineacion = conviertePointsEnPersonalitats(contrarios);
		
		
		if(mejoresInterceptoresContrarios==null){
			mejoresInterceptoresContrarios = new Juegaytoma[alineacion.length];
			Personalitat personalitatAux = null;
			PelotaAnalista pelotaAInterceptarAux=null;
			int indexPelotaAux = 99;
			
			for(int i=0; i<alineacion.length ; i++){
				if (!FutbolTools.estaEnVector(excluir, i)){
				personalitatAux = alineacion[i];
				personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad));
				pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
				indexPelotaAux = trayectoria.indexOf(pelotaAInterceptarAux);
				
				mejoresInterceptoresContrarios[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
				}else{
					personalitatAux = alineacion[i];
					personalitatAux.setPelotaAInterceptar(getPelotaAInterceptarTemporal(trayectoria,personalitatAux,personalitatAux.velocidad,9));
					pelotaAInterceptarAux = personalitatAux.getPelotaAInterceptar();					
					indexPelotaAux = 999;
					mejoresInterceptoresContrarios[i] = new Juegaytoma(i,personalitatAux,indexPelotaAux,pelotaAInterceptarAux);
				}
			}
			
			if(mejoresInterceptoresContrarios.length>0){
				
				Arrays.sort(mejoresInterceptoresContrarios, new ComparadorDeIndicesYDistancias());
				
				////////////////////Comprovacion de que funciona
				// for(int i = 0; i<mejoresInterceptores.length;i++)
				// log.debug("MEJOR1: "+mejoresInterceptores[0].indiceJugador+"    MEJOR2: "+mejoresInterceptores[1].indiceJugador);
				////////////////////////////////////
			}
			
		}

		return mejoresInterceptoresContrarios;
	}
	
	
	private Personalitat[] conviertePointsEnPersonalitats(Point[] contrarios){
		Personalitat[] alineacion = new Personalitat[contrarios.length];
		
		for(int i =0; i< contrarios.length ; i++){
			alineacion[i] = new PersonalitatContrario(i,contrarios[i].x,contrarios[i].y,getFuerzaJugadorContrario(i));
		}

		return alineacion;
	}
	/**
	 * Aquest metode retorna la primera PelotaAnalista de la trajectoria <b>"tray"</b> que el jugador <b>puntoJugador</b> amb 
	 * velocitat <b>"velocidad"</b> te temps de chutar.
	 * <p>
	 * <b>nota:</b> Per utilitzar aquest metode us será mes comode utlitzar Tecnico->getMejorInterceptador(); que et torna un array de tots 
	 * els jugadors teus ordenats segons els steps a que estan de chutar la pilota.
	 * <p>
	 * @param tray
	 * @param puntoJugador
	 * @param velocidad
	 * @return Primera PelotaAnalista de la trajectoria <b>"tray"</b> que el jugador <b>puntoJugador</b> amb 
	 * velocitat <b>"velocidad"</b> te temps de chutar.
	 */
	public PelotaAnalista getPelotaAInterceptarTemporal(ArrayList<PelotaAnalista> tray, Point2D puntoJugador, int velocidad){
		return getPelotaAInterceptarTemporal(tray,puntoJugador,velocidad,9);
		
	}
	
	/**
	 * Aquest metode retorna la primera PelotaAnalista de la trajectoria <b>"tray"</b> que el jugador <b>puntoJugador</b> amb 
	 * velocitat <b>"velocidad"</b> te temps de chutar.
	 * <p>
	 * <b>nota:</b> Per utilitzar aquest metode us será mes comode utlitzar Tecnico->getMejorInterceptador(); que et torna un array de tots 
	 * els jugadors teus ordenats segons els steps a que estan de chutar la pilota.
	 * <p>
	 * @param tray
	 * @param puntoJugador
	 * @param velocidad
	 * @param humbral
	 * @return Primera PelotaAnalista de la trajectoria <b>"tray"</b> que el jugador <b>puntoJugador</b> amb 
	 * velocitat <b>"velocidad"</b> te temps de chutar.
	 */
	public PelotaAnalista getPelotaAInterceptarTemporal(ArrayList<PelotaAnalista> tray, Point2D puntoJugador, int velocidad, int humbral)
	{
		int cost=999, costAux=999;
		boolean pelotaEncontrada=false;
		int i=0, iMillor=tray.size()-1, pelotaReserva=tray.size()-1;
		PelotaAnalista pelota;
		
		for( i=0; i< tray.size()&& !pelotaEncontrada; i++)
		{
			pelota = tray.get(i);
			
			if (Math.round(pelota.velocidad)<15){
				
				
				
				cost = FutbolTools.turnosHastaPunto(puntoJugador,velocidad,pelota,humbral);
				
				costAux = FutbolTools.turnosHastaPunto(puntoJugador,velocidad,pelota,10);
				if(costAux<=i&&!pelotaEncontrada){
					pelotaReserva = i;
				}
				
				
				// Primer chequejo si te temps d'arribar a la pilota. Comparo turn de trajectoria amb "cost" que equival a turns que tardarà a arribar a la posició.
				if(cost<=i&&!pelotaEncontrada){
					iMillor = i;
					pelotaEncontrada=true;
				}
			}
		}
		
		if(iMillor==tray.size()-1){
			iMillor=pelotaReserva;
		}
		
		
		return tray.get(iMillor);
	}
	/**
	 * Te da la posicion donde tirar la pelota (hay que hace pasePreciso) para seguir con el control.
	 * 
	 * @param xJugador donde vas a ir
	 * @param yJugador donde vas a ir
	 * @param stepsPerill tener en cuenta los jugadores que estan a stepsPerill de mi.
	 * @return
	 */
	public Point2D.Double getPosicionDeToque(double xJugador, double yJugador, Point2D miPelota, double stepsPerill)
	{
		Point  contrarios[] = ultimaSJ.getContrario();
		//ArrayList contrariosCercanos = new ArrayList();
		
		int i, cercanos=0;
		double anguloDefinitivo;
		Point [] anguloTmp = new Point[100];
		int distancia = 5;
		int angulosSumados = 0;
		Point2D.Double posPelota = new Point2D.Double();
		
		for(i=0; i<contrarios.length; i++)
		{
			if(contrarios[i].distance(miPelota.getX(),miPelota.getY()) < stepsPerill * getVelocidadJugadorContrario(i) +16)
			{
				
					anguloTmp[cercanos++]=  contrarios[i];
		
			}
		}
				
		
			log.debug("Cercanos: "+cercanos);
			switch(cercanos){
			
			case 1:
				double ang1 = FutbolTools.calcAngulo(xJugador, yJugador, anguloTmp[0].x, anguloTmp[0].y);
				
	
				log.debug("anguloAEvitar:"+Math.toDegrees(ang1));
				anguloDefinitivo= General.corregirAngulo(ang1+Math.PI); //Angle oposat +180º
				log.debug("anguloParaPelota:"+Math.toDegrees(anguloDefinitivo));

				break;
				
			case 2:
				double[] puntoDelMedio = new double[2];
				double anguloContrarios = -999;
				double anguloMedio = -999;
				double dist2 = 0;
				
				anguloContrarios = FutbolTools.calcAngulo(anguloTmp[0], anguloTmp[1]);
				dist2 = anguloTmp[0].distance(anguloTmp[1]);
				puntoDelMedio = getPuntoMedio(anguloTmp[0],anguloTmp[1]);
				anguloMedio = FutbolTools.calcAngulo(xJugador, yJugador, puntoDelMedio[0],puntoDelMedio[1]);
				anguloDefinitivo= General.corregirAngulo(anguloMedio+Math.PI);
				
				break;
				
			//case 3:
			//	break;
				
			default:
			posPelota.x = xJugador;
			posPelota.y = yJugador;
			return posPelota;
			
					
			
			
			}

		posPelota.x = xJugador + Math.cos(anguloDefinitivo)*distancia;
		posPelota.y = yJugador + Math.sin(anguloDefinitivo)*distancia;
		
		return posPelota;
	}
	
	public double[] getPuntoMedio(Point2D puntoOrigen, Point2D puntoFinal){
		double[] puntoDelMedio = new double[2];
		double anguloContrarios = -999;
		double dist2 = 0;
		
		anguloContrarios = FutbolTools.calcAngulo(puntoOrigen, puntoFinal);
		dist2 = puntoOrigen.distance(puntoFinal);
		puntoDelMedio[0] = puntoOrigen.getX() + (dist2/2)*Math.cos(anguloContrarios);
		puntoDelMedio[1] = puntoOrigen.getY() + (dist2/2)*Math.sin(anguloContrarios);
		return puntoDelMedio;
	}
	
	
	
	public double[][] calcularRectes(Point2D centre,double posContrarios[][], double resolucion, double radi, double aMin, double aMax, double anguloDeseado)
	{
		
		resolucion = General.corregirAngulo(toRadians(resolucion));
		
		int numRectes = (int)floor((aMax-aMin)/resolucion);
		
		double rectes[][] = new double[numRectes][3];
		
		// INI
		int i;
		
		for(i = 0; i < numRectes; i++)
		{
			// CHULETA
			rectes[i][0] = radi; 															// distancia al contrario
			rectes[i][1] = aA(aMin+i*resolucion, anguloDeseado); 	// angulo al contrario
			rectes[i][2] = 0; 																// puntuacion del camino
		}
		
		
		
		// Retallar rectes contra contraris
		retallarRectesContraContraris(posContrarios, rectes, radi, anguloDeseado);
		
		
		// Retallar rectes contra parets
		retallarRectesContraParets(centre, rectes, radi, anguloDeseado);
		
		
		//pintarRectes(centre,rectes);
		//pintarFeixRectes(centre,rectes,radi,Color.red);
		
		return rectes;
	}
	
	/*
	public double []  trobarAnglesDespejaos(double[][] posContrarios, double[][] rectes, double radi, double anguloMinimo, double anguloMaximo){
		double[] anglesDefinitius;
		double[] totsElsAngles = new double[200];
		double 	angleInici=999,angleFinal=-999;
		int numAngles=0;
		
		
		for(int i=0; i < posContrarios.length; i++)
		{

				if(posContrarios[i][0] < 10)
					posContrarios[i][0] = 10;		
				
				
				angleInici 	= posContrarios[i][1] + (asin(10/posContrarios[i][0]));
				angleFinal	= posContrarios[i][1] - (asin(10/posContrarios[i][0]));
			
				//log.debug("a de: "+angleInici+" fins a "+angleFinal);
				
				
				if(posContrarios.length==1){
					if(angleFinal<=anguloMinimo){
						totsElsAngles[numAngles++]=angleInici;//anguloInicio
						totsElsAngles[numAngles++]=anguloMaximo;
						break;
					}else  if(angleInici>=anguloMaximo){
							totsElsAngles[numAngles++]=anguloMinimo;
							totsElsAngles[numAngles++]=angleFinal; //anguloFinal
							break;
						
					}else
					{
					totsElsAngles[numAngles++]=anguloMinimo; //anguloInicio
					totsElsAngles[numAngles++]=angleFinal; //anguloFinal
					totsElsAngles[numAngles++]=angleInici; //anguloInicio
					totsElsAngles[numAngles++]=anguloMaximo;
					}
				}else if(i==0){
					if(angleFinal<=anguloMinimo&&angleInici>=anguloMaximo){
						totsElsAngles[numAngles++]=(anguloMaximo+anguloMinimo)/2;
						totsElsAngles[numAngles++]=(anguloMaximo+anguloMinimo)/2;
					}else if(angleFinal<=anguloMinimo){
						totsElsAngles[numAngles++]=angleInici;//anguloInicio
					}else {
						totsElsAngles[numAngles++]=anguloMinimo; //anguloInicio
						totsElsAngles[numAngles++]=angleFinal; //anguloFinal
						totsElsAngles[numAngles++]=angleInici; //anguloInicio
					}
				}else if(i==posContrarios.length-1){
					if(angleInici>=anguloMaximo){
						totsElsAngles[numAngles++]=angleFinal; //anguloFinal
					}else{
						totsElsAngles[numAngles++]=angleFinal;//anguloFinal
						totsElsAngles[numAngles++]=angleInici;//anguloInicio
						totsElsAngles[numAngles++]=anguloMaximo;//anguloFinal
					}
					
				} else{
					
					if(angleFinal<=anguloMinimo){
						totsElsAngles[numAngles++]=angleInici;//anguloInicio
						break;
					}
						
					if(angleInici>=anguloMaximo){
						totsElsAngles[numAngles++]=angleFinal; //anguloFinal
						break;
					}
					
	
					totsElsAngles[numAngles++]=angleFinal;//anguloFinal
					totsElsAngles[numAngles++]=angleInici;//anguloInicio
				}
				
				
				

		}
		

		totsElsAngles = FutbolTools.arrayCopy(totsElsAngles,numAngles);
		log.debug("num rectes = "+numAngles);
		log.debug("num rectes = "+totsElsAngles.length);
		
		anglesDefinitius = filtrarAngles(totsElsAngles);
		return anglesDefinitius;
	}
	*/
	
	
	public double [][]  trobarAnglesDespejados(double [][] rectes, double radi, double anguloDeseado){
		double [][] anglesDefinitiu;
		double [][] anglesLargo = new double[100][2];
		boolean lineaAnteriorDespejada;
		boolean lineaActualDespejada;
		boolean primeraLineaDespejada;
		int anglesAfegits=0;
		int i=0, d=0,indexAnlgeInici,indexAngleFinal;

		primeraLineaDespejada = (rectes[d++][0]==radi);
	
		for(; d<rectes.length && !primeraLineaDespejada; d++){
			primeraLineaDespejada = (rectes[d][0]==radi);
		}
		d--; //Per apuntar a la ultima linea mirada
		
		
		/// Si no s'ha trobat ni una recta bona --> return una angle inicial i final iguals
		if(d==rectes.length-1&&!(rectes[d][0]==radi)){
			log.debug("NOO POT SEEER!");
			anglesLargo[0][0]= aA((rectes[0][1]-rectes[rectes.length-1][1])/2, anguloDeseado); //angle mig
			anglesLargo[0][1]= aA((rectes[0][1]-rectes[rectes.length-1][1])/2, anguloDeseado); //angle mig
			anglesAfegits++;
			anglesDefinitiu = FutbolTools.arrayCopy(anglesLargo,anglesAfegits);
			return anglesDefinitiu;
		}
			
	
		indexAnlgeInici = d;
		
		lineaAnteriorDespejada = rectes[indexAnlgeInici][0]==radi; //Ha de ser sempre true;
		anglesLargo[anglesAfegits][0] = rectes[indexAnlgeInici][1];
		
		for( i = indexAnlgeInici+1; i<rectes.length ; i++){
			lineaActualDespejada = rectes[i][0]==radi;
			
			if(!lineaActualDespejada&&lineaAnteriorDespejada){
				anglesLargo[anglesAfegits][1] = rectes[i-1][1]; //set angle final
				anglesAfegits++;//set angle afegit
			}
		
			if(lineaActualDespejada&&!lineaAnteriorDespejada){
				anglesLargo[anglesAfegits][0] = rectes[i][1]; //set angle inici
			}
		
			lineaAnteriorDespejada = lineaActualDespejada;
		
		}
		
		i-- ;//Per apuntar a la ultima linea mirada
		
		indexAngleFinal=i;
		
		if(rectes[indexAngleFinal][0]==radi){
			anglesLargo[anglesAfegits][1] = rectes[indexAngleFinal][1]; //set angle final
			anglesAfegits++;										
		}
		
		
		//Chequeig de angle PI; // Deshabilitar la partició d'esfera a l'angle PI;
		/*
		 * 
		 if(anglesAfegits>1&& Math.abs(anglesLargo[0][0]-anglesLargo[anglesAfegits-1][1])<Math.toRadians(3)){
			anglesLargo[0][0] = aA(anglesLargo[0][0] + anglesLargo[anglesAfegits-1][0]-anglesLargo[anglesAfegits-1][1], anguloDeseado);
			
			//quitar el ultimo angulo
			anglesAfegits--;
		}
		*/
		
		
		anglesDefinitiu = FutbolTools.arrayCopy(anglesLargo,anglesAfegits);
		
	//	log.debug("1-Num rectes: "+rectes.length);
	//	log.debug("2-Num rectes: "+rectes.length);
	//	log.debug("1-Num parelles: "+anglesAfegits);
	//	log.debug("2-Num parelles: "+anglesDefinitiu.length);
		return anglesDefinitiu;
	}
	
	
	private double [] filtrarAngles(double [] totsElsAngles){
		double [] anglesFiltrats = new double[totsElsAngles.length];
		double [] anglesFiltratsReduit;
		int iTots=0, iFilt=0;
		
		for(; iTots<totsElsAngles.length ;){
			
			
			anglesFiltrats[iFilt++] = General.corregirAngulo(totsElsAngles[iTots++]);
			//log.debug("vTotsAngles:"+totsElsAngles[iTots-1]+" vAnglesFiltrats:"+anglesFiltrats[iFilt-1]);
		
		}
		anglesFiltratsReduit = FutbolTools.arrayCopy(anglesFiltrats,iFilt);
		
		return anglesFiltratsReduit;
	}
	
	
	public static void sort(double a[][], int indexAOrdenar , int numElements)
	{
		
		double D=0,A=0,I=0;
		
		for (int i = a.length; --i >= 0;)
		{
			boolean flipped = false;
			for (int j = 0; j < i; j++) {
				if (a[j][indexAOrdenar] > a[j + 1][indexAOrdenar]) {
					
					D = a[j][0];
					if(numElements>1)
						A = a[j][1];
					if(numElements>2)
						I = a[j][2];
					
					a[j][0] = a[j + 1][0];
					if(numElements>1)
						a[j][1] = a[j + 1][1];
					if(numElements>2)
						a[j][2] = a[j + 1][2];
					
					a[j + 1][0] = D;
					if(numElements>1)
						a[j + 1][1] = A;
					if(numElements>2)
						a[j + 1][2] = I;
					flipped = true;
				}
			}
			if (!flipped) {
				return;
			}
		}
	}
	
	
	private boolean entre(double min, double num, double max)
	{
		return (num<min)? false : (num > max)? false : true;
	}


	public Point2D.Double polarACartesiana(Point2D centro,double rad, double ang)
	{
		return new Point2D.Double(centro.getX()+rad*cos(ang),centro.getY()+rad*sin(ang));
	}
	
	
	private void retallarRectesContraContraris(double[][] posContrarios, double[][] rectes, double radi, double anguloDeseado){
		for(int i=0; i < posContrarios.length; i++)
		{
		
			if((posContrarios[i][0]-10)<radi){
			
				if(posContrarios[i][0] < 10)
					posContrarios[i][0] = 10;
							
				double 	angleInici 	= aA((posContrarios[i][1] + asin(10/posContrarios[i][0])), anguloDeseado),
								angleFinal	= aA((posContrarios[i][1] - asin(10/posContrarios[i][0])), anguloDeseado);
				
				for(int j=0; j < rectes.length ; j++)
				{
					if(rectes[j][1] <= angleInici && rectes[j][1] >= angleFinal)
					{
						rectes[j][0] = min(Tecnico.trim(posContrarios[i][0]-10,0,radi),rectes[j][0]);
						
					}
					
					/*else if((angleInici>=0&&angleInici<PI)&&(angleFinal>PI&&angleFinal<360)){
						if(General.corregirAngulo(rectes[j][1]) <= angleInici && General.corregirAngulo(rectes[j][1]) >= 0)
						{
							rectes[j][0] = min(Tecnico.trim(posContrarios[i][0]-10,0,radi),rectes[j][0]);
						}
						if(General.corregirAngulo(rectes[j][1]) <= 2*PI && General.corregirAngulo(rectes[j][1]) >= angleFinal)
						{
							rectes[j][0] = min(Tecnico.trim(posContrarios[i][0]-10,0,radi),rectes[j][0]);
						}
					}else if((angleInici==0)&&(angleFinal==PI))
					{
						if(General.corregirAngulo(rectes[j][1]) >= angleFinal || General.corregirAngulo(rectes[j][1]) == 0)
						{
							rectes[j][0] = min(Tecnico.trim(posContrarios[i][0]-10,0,radi),rectes[j][0]);
						}
						
					}
					*/
					
				}
			}

		}
	}
	
	private void retallarRectesContraParets(Point2D centre, double[][] rectes, double radi, double anguloDeseado){
		double 	mr = 0,	br = 0;
		Color color = Color.WHITE;
		double tall[] = new double[2];
		
		boolean noTocar = false;
		int state = 0;

		
		
		double [][] angulosLimite = new double [4][2];
		
		angulosLimite[0][0] = aA(calcAngulo(centre, 160,-120), anguloDeseado);
		angulosLimite[1][0] = aA(calcAngulo(centre, 160,120), anguloDeseado);
		angulosLimite[2][0] = aA(calcAngulo(centre, -160,120), anguloDeseado);
		angulosLimite[3][0] = aA(calcAngulo(centre, -160,-120), anguloDeseado);
		angulosLimite[0][1] = 3;
		angulosLimite[1][1] = 0;
		angulosLimite[2][1] = 1;
		angulosLimite[3][1] = 2;
		
		
		//Ordenar!
		sort(angulosLimite, 0, 2);
		
		for(int i=0; i<rectes.length; i++)
		{
			Point2D.Double p = polarACartesiana(centre, rectes[i][0], rectes[i][1]);
			mr = (p.y - centre.getY() ) / (p.x - centre.getX());
			br = p.y - mr*p.x;
			
			
			
			
			
			
			if( rectes[i][1] > angulosLimite[0][0] ) 
			{
	
				if( rectes[i][1]> angulosLimite[1][0] )
				{
					if( rectes[i][1] > angulosLimite[2][0] )
					{
						if( rectes[i][1] > angulosLimite[3][0] )
						{
							state = (int)angulosLimite[0][1];
							//log.debug("angle de recta:"+ Math.toDegrees(rectes[i][1])+" - STATE "+angulosLimite[0][1]);
						}
						else{
							state = (int)angulosLimite[3][1];
							//log.debug("angle de recta:"+ Math.toDegrees(rectes[i][1])+" - STATE "+angulosLimite[3][1]);
						}
					}
					else{ 
						state = (int)angulosLimite[2][1];
						//log.debug("angle de recta:"+ Math.toDegrees(rectes[i][1])+" - STATE "+angulosLimite[2][1]);
					}
				}
				else{
					state = (int)angulosLimite[1][1];
					//log.debug("angle de recta:"+ Math.toDegrees(rectes[i][1])+" - STATE "+angulosLimite[1][1]);
				}
			}else{
				state = (int)angulosLimite[0][1];
				//log.debug("angle de recta:"+ Math.toDegrees(rectes[i][1])+" - STATE "+angulosLimite[0][1]);
			}
			
			if( (p.y >  120) || (p.y < -120) || (p.x >  160) || (p.x < -160) ) // A
			{	
				switch(state)
				{
				case 0: // Paret Dreta
					
					tall[0] = 160;
					tall[1] = tall[0] * mr + br;
					
					color = Color.BLUE;
					
					if(tall[1]<30&&tall[1]>-30){
						noTocar=true;
					}
					
					if(!entre(-120,tall[1],120))
						state++;
					break;
				case 1: // Paret Baix
					tall[1] = 120;
					if(Double.isInfinite(mr)||Double.isNaN(mr))
						tall[0] = centre.getX();
					else
						tall[0] = (tall[1] - br) / mr;
					
					color = Color.YELLOW;
					
					if(!entre(-160,tall[0],160))
						state++;
					break;
				case 2: // Paret Esquerra
					tall[0] = -160;
					tall[1] = tall[0] * mr + br;
					
					color = Color.GREEN;
					if(!entre(-120,tall[1],120))
						state++;
					break;
				case 3: // Paret Dalt
					tall[1] = -120;
					if(Double.isInfinite(mr)||Double.isNaN(mr))
						tall[0] = centre.getX();
					else
						tall[0] = (tall[1] - br) / mr;
					
					color = Color.RED;
					
					if(!entre(-160,tall[0],160))
						state++;
					break;
				case 4: // Paret Dreta
					tall[0] = 160;
					tall[1] = tall[0] * mr + br;
					color = Color.BLUE;
					
					if(tall[1]<30&&tall[1]>-30){
						noTocar=true;
					}
					
					if(!entre(-120,tall[1],120))
						state++;
					break;
				}
				
				if(!noTocar){
					rectes[i][0] = centre.distance(tall[0],tall[1]);
				}
				
				//drawLine(centre, rectes[i][0], rectes[i][1], color);
				
			
				
			}
			
			noTocar = false;
			tall[0] = tall[1] = 0;
		}
		
	}
	
	
	

	
	
	
	
	/**
	 * Retorna un int cualitatPase. Si es menor que zero hi ha un contrari en trajectoria.
	 * Com major es cualitatPase mes segura es la trajectoria.
	 *
	 *
	 * @param jugador - Personalitat del jugador origen
	 * @param pelotaOrigen - pilota actual
	 * @param indexJugadorDesti - index del jugador que rep el pase
	 * @return int cualitatPase
	 */
	public int contrariEnTrajectoria(Personalitat jugador,PelotaAnalista pelotaOrigen,int indexJugadorDesti)
	{		
		double[]  puntoDestinoOptimo = FutbolTools.pasePreciso(jugador, pelotaOrigen, indexJugadorDesti);
		int fuerza = FutbolTools.getFuerzaEfectivaSegunDestino(jugador.fuerza, jugador, puntoDestinoOptimo[0], puntoDestinoOptimo[1]);
		
		return contrariEnTrajectoriaPuntoPreciso(jugador, fuerza, pelotaOrigen, indexJugadorDesti);
	}
	
	public int contrariEnTrajectoriaPuntoPreciso(Point2D jugador, int fuerzaJugador, PelotaAnalista pelotaOrigen,int indexJugadorDesti)
	{
		Personalitat jugadorDesti = getAlineacion()[indexJugadorDesti];
		ArrayList <PelotaAnalista> trayecto = new ArrayList<PelotaAnalista>();
		
		PelotaAnalista pilotaHipotetica = FutbolTools.createPelotaSegunDestino(jugador, fuerzaJugador, pelotaOrigen, jugadorDesti.x, jugadorDesti.y);
		
		// trayecto son tots els punts on passara la pilota
		FutbolTools.calculTrajectoria(pilotaHipotetica,trayecto);

		PelotaAnalista pelIntercep = this.getPelotaAInterceptarTemporal(trayecto, jugadorDesti, jugadorDesti.velocidad, 5);
	
		Juegaytoma meuInterceptor = new Juegaytoma(indexJugadorDesti,jugadorDesti,trayecto.indexOf(pelIntercep),pelIntercep);
		Juegaytoma[] contrarisInterceptor = getMejoresInterceptoresContrariosHipotetico(trayecto, null);
		
		if(meuInterceptor.indicePelota==0)
			meuInterceptor.indicePelota++;

		/*for(int i=0;i<trayecto.size();i++)
		{
			fillOval(trayecto.get(i), 2, Color.cyan);
		}/*
		
		/*drawLine(meuInterceptor.puntoJugador.getX(), meuInterceptor.puntoJugador.getY(), meuInterceptor.puntoObjetivo.getX(), 
				 meuInterceptor.puntoObjetivo.getY(), Color.white);
		drawLine(contrarisInterceptor[0].puntoJugador.getX(), contrarisInterceptor[0].puntoJugador.getY(), 
				 contrarisInterceptor[0].puntoObjetivo.getX(), contrarisInterceptor[0].puntoObjetivo.getY(), Color.black);
		*/
		//System.err.println("meu interceptor--> index: "+meuInterceptor.indiceJugador+" steps: "+meuInterceptor.indicePelota+"\n"+
		//				   "contrari       --> index: "+contrarisInterceptor[0].indiceJugador+" steps: "+contrarisInterceptor[0].indicePelota);
		
		return (contrarisInterceptor[0].indicePelota - meuInterceptor.indicePelota);
	} 
	
	public int contrariEnTrajectoria(Personalitat jugador,PelotaAnalista pelotaOrigen,Point2D puntoDestino)
	{
		
		
		
		ArrayList <PelotaAnalista> trayecto = new ArrayList<PelotaAnalista>();
		FutbolTools.calculTrajectoriaSegunPuntoDestino(jugador,pelotaOrigen, trayecto,puntoDestino);
		Juegaytoma[] misInterceptores = getMejoresInterceptoresHipotetico(trayecto, null);
		Juegaytoma[] susInterceptores = getMejoresInterceptoresContrariosHipotetico(trayecto, null);
		
		return (susInterceptores[0].indicePelota - misInterceptores[0].indicePelota);
	
	}
	
	/**
	 * Retorna un array amb els punts x i y on xutar la pilota perque reboti i arribi al jugador desti. 
	 * Comprova si hi ha contraris en trajectoria, si el jugador te poca forsa i
	 * si el pase es masa dolent, si es aixi retorna null.
	 * 
	 * @param jugadorOrigen - Personalitat del jugador que fa el pase
	 * @param bolaOrigen - PelotaAnalista actual (tecnico.getBola)
	 * @param jugadorDesti - Personalitat del jugador que rep el pase
	 * @return Point2D si es pot fer el pase - null si hi ha un contrari en trajectoria
	 */
	public double [] paseRebote(Personalitat jugadorOrigen,PelotaAnalista b,Personalitat jugadorDesti)
	{
		PelotaAnalista bolaOrigen = b.getCopia();
		double angleRelatiu =0;
		double xRebote=0;
		double yRebote = 0;
		Point2D puntDestiRel;
		double [] p = null;
		
		// descartem els pases rebotes mol dolents
		if(bolaOrigen.distance(jugadorDesti)<30 || jugadorDesti.x - bolaOrigen.x <30
		   || (bolaOrigen.y > -30 && bolaOrigen.y < 30) // si estic mol lluny de paret
		   || jugadorDesti.x < jugadorOrigen.x			// si el jugador esta enrere
		   || bolaOrigen.distance(jugadorDesti)>80) 	// i el jugador esta mol lluny
			return null;
			
		
		// calculem el punt de rebote amb la paret
		Point2D puntRebote = calculPuntIntersec(bolaOrigen.x, bolaOrigen.y, jugadorDesti.x, jugadorDesti.y);
	
		xRebote = puntRebote.getX();
		yRebote = puntRebote.getY();
		
		double distRelativa = jugadorDesti.distance(xRebote,yRebote);
		
		angleRelatiu = FutbolTools.calcAngulo(bolaOrigen.x,bolaOrigen.y,xRebote, yRebote); 
		
		puntDestiRel = new Point2D.Double(xRebote+ distRelativa*Math.cos(angleRelatiu) , yRebote + distRelativa*Math.sin(angleRelatiu));
		
		if(contrariEnTrajectoria(jugadorOrigen, bolaOrigen, puntDestiRel) >= 0)
		{
			//drawLine(bolaOrigen.x,bolaOrigen.y,puntDestiRel.getX(),puntDestiRel.getY(),Color.white);
			p = FutbolTools.toquePrecisoSinParedes(jugadorOrigen, bolaOrigen, puntDestiRel);
			//drawLine(bolaOrigen.x,bolaOrigen.y,p[0],p[1],Color.red);
	
			// si el jugador no te prou forsa no fem el pase no puc cridar a futbolTools!!!!
			if(FutbolTools.distanciaMaximaDePelota(jugadorOrigen.fuerza) -5 < bolaOrigen.distance(p[0],p[1]))
				p = null;
		}
		return p;
	}
	
	// funcio utilitzada en el paseRebote
	public Point2D calculPuntIntersec(double xOrigen,double yOrigen,double xDesti,double yDesti)
	{
		double yIntersec, xIntersec;
		Point2D punt = null;
		
		if(yOrigen < 0)
		{
			yIntersec = -120;
		}
		else
			yIntersec = 120;
		
		// perque no peti...
		if(xOrigen == xDesti)
			return null;
		
		//primera recta y=mx+a puntOrigen a y=yIntersec
		//calculem alfa
		double alfa = FutbolTools.calcAngulo(xOrigen, yOrigen, xDesti, yIntersec);
		// calculem pendent
		double m = Math.tan(alfa);
		// calculem a substituint y= yOrigen x=xOrigen
		double a = yOrigen - (m * xOrigen);
		
		//segona recta y=px+b puntDesti a y=yIntersec
		//calculem beta
		double beta = FutbolTools.calcAngulo(xOrigen, yIntersec, xDesti, yDesti);
		//pendent
		double p = Math.tan(beta);
		// calculem b substituint y=yDesti x=xDesti
		double b = yDesti -(p * xDesti);
		
		//substituim al sistema per trobar x
		xIntersec = (b-a) / (m-p);
			
		punt = new Point2D.Double(xIntersec,yIntersec);
		
		double yReal = m*xIntersec +a;
		double yReal2 = p*xIntersec +b;

		return punt;
	}
	
	// VISOR
	public double getAnguloSegunPuntoDeseado(double[][] angles, Point2D centro, Point2D puntoDeseado){
		int i = 0;
		double mejorAngulo = -999;
		double [] angulosMedios = new double[angles.length];
		double anguloDeseado = FutbolTools.calcAngulo(centro,puntoDeseado);
		int numAngulosBuenos=0;
		
		angulosMedios[i] = FutbolTools.aA(angles[i][0] + (angles[i][1]-angles[i][0])/2, anguloDeseado);
		
		double dif = Math.abs(angles[i][1]-angles[i][0]);
		//log.debug("CalidadAngulo:"+Math.toDegrees(dif));
		
		if( dif>Math.toRadians(10)){
			mejorAngulo=angulosMedios[i];
		}

		for(i++; i<angles.length ; i++)
		{
			angulosMedios[i] = FutbolTools.aA(angles[i][0] + (angles[i][1]-angles[i][0])/2, anguloDeseado);
			
			dif = Math.abs(angles[i][1]-angles[i][0]);
			//log.debug("CalidadAngulo:"+Math.toDegrees(dif));
			
			if( dif>Math.toRadians(10)){
				if(Math.abs(angulosMedios[i]-anguloDeseado)<Math.abs(mejorAngulo-anguloDeseado)){
					
					mejorAngulo=angulosMedios[i];
				}
			}
		}
		
		if(mejorAngulo==-999){
			return mejorAngulo;
		}
		
		/*
		for(int j=0; j<angles.length;j++){
			this.drawLine( centro,  	50,  angulosMedios[j], Color.YELLOW);		
		}
		this.drawLine( centro,  	100,  mejorAngulo, Color.BLUE);
		this.drawLine( centro,  	centro.distance(puntoDeseado),  anguloDeseado, Color.LIGHT_GRAY);
		*/
		
		return mejorAngulo;
	}
	public double[][] analitzarContraris(Point2D centre, double radi, double anguloMinimo, double anguloMaximo, double anguloDeseado) {
		Point contrarios[] = ultimaSJ.getContrario();
		double posContrarios[][] = new double[11][3];
		double anguloEnemigo, distAux;
		
		int i,numContr;
		for (i = 0, numContr=0; i < posContrarios.length;i++) {
			
			distAux =centre.distance(contrarios[i]);
			anguloEnemigo = FutbolTools.aA(FutbolTools.calcAngulo(centre,contrarios[i].x, contrarios[i].y), anguloDeseado);
			if(i==10){
			//log.debug("aAux:"+Math.toDegrees(anguloEnemigo)+" aMin:"+Math.toDegrees(anguloMinimo));
			//log.debug("aAux:"+Math.toDegrees(anguloEnemigo)+" aMax:"+Math.toDegrees(anguloMaximo)+"\n");
			}
			
			if((centre.distance(contrarios[i])-10<radi) && (anguloEnemigo>anguloMinimo&&anguloEnemigo<anguloMaximo)){
				posContrarios[numContr][0] = distAux;
				posContrarios[numContr][1] = anguloEnemigo;
				posContrarios[numContr][2] = i;
				numContr++;
			}
		}
		
		//log.debug("Num contrarios:"+ numContr);
		
		posContrarios = arrayCopy(posContrarios,numContr);
		sort(posContrarios, 1,3);
		
		return posContrarios;
	}
	/*private double[] calcularInterseccio(double br, double mr, double bp, double mp)
	{
		double p[] = new double[2];
		p[0] = (bp-br) / (mr-mp);
		p[1] = (bp*mr-br*mp)/(mr-mp);
		
		log.debug("p = (" + p[0]+","+p[1]+")");
		
		return p;
	}*/
	public double[][] getRutasLibres(Point2D centre, double radi, Point2D puntoDeseado)
	{
		return getRutasLibres(centre, radi, puntoDeseado,(Math.PI-Math.PI/10));
	}
	
	public double[][] getRutasLibres(Point2D centre, double radi, Point2D puntoDeseado, double anguloObertura)
	{
		double 	anguloDeseado 	= FutbolTools.calcAngulo(centre,puntoDeseado);
		double 	anguloMaximo 	= FutbolTools.aA(anguloDeseado+anguloObertura, anguloDeseado);
		double  	anguloMinimo 	= FutbolTools.aA(anguloDeseado-anguloObertura, anguloDeseado);
		double 	contraris[][], angles[][], rectes[][];
		
		contraris = analitzarContraris(centre, radi,anguloMinimo, anguloMaximo, anguloDeseado);
		/*
		for(int j =0; j<contraris.length; j++){
			drawLine(centre, contraris[j][0], contraris[j][1], Color.PINK);
		}
		*/
		rectes = calcularRectes(centre, contraris, 2, radi, anguloMinimo, anguloMaximo, anguloDeseado); //Es pintaran rectes des de angMin fins a angMax
		
		//pintarFeixRectes(centre, rectes, radi, Color.red);
		
		angles = trobarAnglesDespejados(rectes, radi, anguloDeseado);
		
		/*
		for(int i=0; i< angles.length ; i++){
			drawLine(centre, radi, angles[i][0], Color.BLACK);
			drawLine(centre, radi, angles[i][1], Color.BLACK);
		}*/
		
		
		
		return angles;
	}
	
	
	public double[] irHaciaConEvasion(Personalitat jugador, double[][] angles, Point2D puntoDeseado)
	{
		double 		anguloElejido;
		double[]	puntoElejido = new double[2];
		
		anguloElejido = getAnguloSegunPuntoDeseado(angles, jugador, puntoDeseado);
		
		if(anguloElejido==-999){
			return null;
		}

		puntoElejido[0] = jugador.x + jugador.velocidad*Math.cos(anguloElejido) ;
		puntoElejido[1] = jugador.y + jugador.velocidad*Math.sin(anguloElejido) ;
		
		return puntoElejido;
	}
	
	/**Marcaje de un contrario con un jugador, primera opcion:
	 * Si le pasa un distanciaMarcaje positivo el jugador marca en el angulo entre el contrario
	 * Segunda opcion:
	 * distanciaMarcaje positiva: Si la velocidad de tu jugador es menor
	 * que la del contrario marca en la misma posicion que el contrario sino marca
	 * a distancia distanciaMarcaje en positivo cubriendo entre la pelota y el contrario
	 *  
	 * 
	 * @param jugador jugador que marca
	 * @param contrario contrario marcado
	 * @param distanciaMarcaje distancia en pixel a la que quieres marcar
	 * @return Devuelve la posicion a la cual tiene que ir tu jugador
	 */
	public Point2D.Double marcaje(int jugador, int contrario, int distanciaMarcaje)
	{
		Point2D.Double puntoACubrir = new Point2D.Double();
		Point contrarios[] = ultimaSJ.getContrario();
		Personalitat marcador = getAlineacion()[jugador];
		PelotaAnalista pelota = getMiPelota();
		double posicionX;
		double posicionY;
		double angulo;
			
		if(distanciaMarcaje < 0)
		{
			if (marcador.velocidad < getVelocidadJugadorContrario(contrario))
			{
				puntoACubrir.x = contrarios[contrario].getX();
				puntoACubrir.y = contrarios[contrario].getY();
			}	
			else
			{
				distanciaMarcaje = Math.abs(distanciaMarcaje);
				angulo = FutbolTools.calcAngulo(contrarios[contrario], pelota.getX(), pelota.getY());
				angulo = FutbolTools.corregirAnguloPI(angulo);
				posicionX = contrarios[contrario].getX();
				posicionY = contrarios[contrario].getY();
				posicionX+= Math.cos(angulo)*distanciaMarcaje;
				posicionY+= Math.sin(angulo)*distanciaMarcaje;
				puntoACubrir.x = posicionX;
				puntoACubrir.y = posicionY;
			}
		}
		else
		{
			angulo = FutbolTools.calcAngulo(contrarios[contrario], pelota.getX(), pelota.getY());
			angulo = FutbolTools.corregirAnguloPI(angulo);
			posicionX = contrarios[contrario].getX();
			posicionY = contrarios[contrario].getY();
			posicionX+= Math.cos(angulo)*distanciaMarcaje;
			posicionY+= Math.sin(angulo)*distanciaMarcaje;
			puntoACubrir.x = posicionX;
			puntoACubrir.y = posicionY;
		}
		return puntoACubrir;
		
	}
	
	/**Igual que marcaje pero sino le pasas la distancia te coje una ditancia de -10
	 * o sea que los lentos marcaran encima y los rapido a distancia 10.
	 * @param jugador
	 * @param contrario
	 * @return
	 */
	
	public Point2D.Double marcaje(int jugador, int contrario)
	{
		return marcaje(jugador, contrario, -10);
	}
	
	/**Decide que jugador marca mejor al contrario.
	 * 
	 * @param jugadores Array de jugadores marcadores
	 * @param contrariosAMarcar Array de contrarios a marcar
	 * @return un array [2][Jugadores.length] donde la primera fila array[0][x] son tus jugadores y array[1][x] son los contrarios ordenados
	 * o sea array [1][1] tienes el mejor contrario al que marca tu array[0][1]
	 */
	public int[][] decidirMarcaje(int jugadores[], int contrariosAMarcar[])
	{
		
		if (contrarioMarcado ==null){
			contrarioMarcado = new int[jugadores.length][2];

			Point contrarios[] = ultimaSJ.getContrario();
			Personalitat[] alineacion = getAlineacion();
			
			int posicionX = 0;
			int posicionY = 0;
			int i = 0;
			int j = 0;
			int w = 0;
			int z = 0;
			boolean lineaBuena = false;
			double matrix[][] = new double[jugadores.length][jugadores.length];
			
			double mejorTiempo =0;
			for (i =0; i< jugadores.length; i++)
			{
				contrarioMarcado[i][1] = -1;
				contrarioMarcado[i][0] = jugadores[i];
			}
			int ladoMatriz = jugadores.length;
			
			//Si no tenemos los mismos jugadores k contrarios pos no va :P
			
			if(jugadores.length != contrariosAMarcar.length)
				throw new java.lang.IllegalArgumentException("jugador.length i contrarios.length tiene que ser igual!!");
			
			//Llenamos la matriz 
			for(i =0; i<jugadores.length; i++)
			{
				for (j=0; j< jugadores.length; j++)
					matrix[i][j] = alineacion[jugadores[i]].distance(contrarios[contrariosAMarcar[j]]); 
			}
			
			
			while(ladoMatriz > 0)
			{
				lineaBuena = false;
				posicionX = 0;
				posicionY = 0;
				mejorTiempo = 9999999;
				
				
				//Buscamos la primera posicion buena
				
				for (i=0; i<jugadores.length; i++){
					
					for(z=0; z<jugadores.length; z++)
					if(matrix[z][i] != -1 && lineaBuena == false){
						mejorTiempo = matrix[z][i];
						posicionX = z;	
						posicionY = i;
						lineaBuena = true;
					}
				}
				
				for( j=0; j<jugadores.length; j++ )
				{
					//Recorremos contrariosAMarcar, si encontramos un mejor tiempo lo guardamos.
					
					if(matrix[posicionX][j] < mejorTiempo && matrix[posicionX][j] != -1)
					{
						mejorTiempo = matrix[posicionX][j];
						posicionY = j;
					}
				}
				
				//recorremos nuestros jugadores para ver si ay alguien que lo marque mejor
				for(w=0; w<jugadores.length; w++)
				{
					
					if(matrix[w][posicionY] < mejorTiempo && matrix[w][posicionY] != -1)
					{
						mejorTiempo = matrix[w][posicionY];
						posicionX = w;
					}
					
				}
				
				//El contrario Marcado se guarda en una matriz donde el indice del Jugador dictimina quien es el Contrio k marca
				//O dixo mas facil el jugador en la posicion jugadores[3][0] marca a contrarioMarcado[3][1]. 
	
				for(i=0; i<jugadores.length; i++  ){
					if (jugadores[i] == jugadores[posicionX])
						contrarioMarcado[i][1]=contrariosAMarcar[posicionY];	
				}
				
				ladoMatriz--;
				
				//Ponemos en -1 los puntos de la matriz que ya an sido usados
				for(i= 0; i < jugadores.length; i++ )
				{
					matrix[i][posicionY]= -1;
					for (j = 0 ; j < jugadores.length; j++)
						matrix[posicionX][j] =  -1;
				}
						
			}
		}
		return contrarioMarcado;
	}
	
	/**Dispara con maxima fuerza a cualquier punto.
	 * 
	 * @param pelota le pasas un pelotanalista
	 * @param chuteCorto el point2D donde kieres chutar la pelota
	 * @return te devuelve el punto donde tienes que chutar para que la pelota 
	 * pase por chutCorto a maxima potencia.
	 */
	public Point2D.Double canyonazo(PelotaAnalista pelota, Point2D chuteCorto)
	{
		Point2D.Double puntoDeChute = new Point2D.Double(0,0);
		double angulo;
		
		if (pelota.distance(chuteCorto) == 0)
			return puntoDeChute;
		
		angulo = FutbolTools.calcAngulo(pelota, chuteCorto);
		angulo = FutbolTools.corregirAnguloPI(angulo);
		puntoDeChute.x = chuteCorto.getX();
		puntoDeChute.y = chuteCorto.getY();
		puntoDeChute.x+= Math.cos(angulo)*70;
		puntoDeChute.y+= Math.sin(angulo)*70;
		
		return puntoDeChute;
	}
	

	/** Igual k canyozazo pero convierte dos puntos X y Y en un Point2D: 
	 * ispara con maxima fuerza a cualquier punto.
	 * 
	 * @param pelota le pasas un pelotanalista
	 * @param posX x donde quieres chutar
	 * @param posY y donde quieres chutar
	 * @returnte devuelve el punto donde tienes que chutar para que la pelota 
	 * pase por chutCorto a maxima potencia
	 */
	public Point2D.Double canyonazo(PelotaAnalista pelota, double posX, double posY)
	{
		Point2D.Double puntoDeChute = new Point2D.Double(posX,posY);

		return canyonazo(pelota, puntoDeChute);
		
	}
	/** despeje de la pelota como ultima opcion
	 * 
	 * @param numJugador 
	 * @return te devuelve el punto menos malo donde hacer el toquePreciso
	 */
	public Point2D despejarPelota(int numJugador)
	{
		
		return despejarPelota(numJugador, 0, 0);
	}
	
	
	public Point2D despejarPelota(int numJugador, double anguloA, double anguloB)
	{
		Personalitat jugador = getAlineacion()[numJugador];
		PelotaAnalista pelota = getMiPelota();
		double distancia = 9999;
		double menorDistancia = 9999;
		Point2D.Double mejorPunto = new Point2D.Double();
		Point2D.Double puntoAleatorio = new Point2D.Double();
		
		Personalitat jugadorRecibidor = null;
		
		int valor = 0;
		int mejorValor = -999;
		
		for(int i=0; i<100; i++)
		{
			puntoAleatorio = crearPuntoAleatorio(jugador, jugador.fuerza, anguloA, anguloB);
			valor = contrariEnTrajectoria(jugador, pelota, puntoAleatorio);
			ArrayList<PelotaAnalista> trayecto = new ArrayList<PelotaAnalista>();
			FutbolTools.calculTrajectoriaSegunPuntoDestino(jugador,pelota,trayecto, puntoAleatorio);
			jugadorRecibidor = getAlineacion()[getMejoresInterceptoresHipotetico(trayecto, null)[0].indiceJugador];
			//fillOval(puntoAleatorio, valor , Color.RED);
			distancia = jugadorRecibidor.distance(puntoAleatorio);
			if ( jugadorRecibidor.numero!=numJugador){
				if(valor > mejorValor ||(valor == mejorValor&& distancia < menorDistancia))
				{
					mejorValor = valor;
					menorDistancia = distancia;
					mejorPunto.x = puntoAleatorio.getX();
					mejorPunto.y = puntoAleatorio.getY();
				}
			}

		}
		//drawLine(jugador.getX(), jugador.getY(), -160, 40, Color.ORANGE);
		//drawLine(jugador.getX(), jugador.getY(), -160, -40, Color.ORANGE);
		//fillOval(mejorPunto, 4 , Color.BLACK);
		//drawArc(-160, 0, 60, Math.PI, 0, Color.white);
		
		return mejorPunto;
	}
	
	public Point2D despejarPelotaParaPortero(int numJugador, double anguloA, double anguloB)
	{
		Personalitat jugador = getAlineacion()[numJugador];
		PelotaAnalista pelota = getMiPelota();
		double distancia = 9999;
		double menorDistancia = 99999;
		Point2D.Double mejorPunto = new Point2D.Double();
		Point2D.Double puntoAleatorio = new Point2D.Double();
		
		Personalitat jugadorRecibidor = null;
		
		int valor = 0;
		int mejorValor = -999;
		
		for(int i=0; i<100; i++)
		{
			puntoAleatorio = crearPuntoAleatorio(jugador, jugador.fuerza, anguloA, anguloB);
			valor = contrariEnTrajectoria(jugador, pelota, puntoAleatorio);
			ArrayList<PelotaAnalista> trayecto = new ArrayList<PelotaAnalista>();
			FutbolTools.calculTrajectoriaSegunPuntoDestino(jugador,pelota,trayecto, puntoAleatorio);
			jugadorRecibidor = getAlineacion()[getMejoresInterceptoresHipotetico(trayecto, null)[0].indiceJugador];
			distancia = jugadorRecibidor.distance(puntoAleatorio);
			if ( jugadorRecibidor.numero!=numJugador){
				if(valor > mejorValor ||(valor == mejorValor&& distancia < menorDistancia))
				{
					mejorValor = valor;
					menorDistancia = distancia;
					mejorPunto.x = puntoAleatorio.getX();
					mejorPunto.y = puntoAleatorio.getY();
				}
			}

		}
		//drawLine(jugador.getX(), jugador.getY(), -160, 40, Color.ORANGE);
		//drawLine(jugador.getX(), jugador.getY(), -160, -40, Color.ORANGE);
		//drawArc(-160, 0, 60, Math.PI, 0, Color.white);
		
		return mejorPunto;
	}

	/** Crea un punto aleatorio
	 * 
	 * @param centro el centro del punto
	 * @param fuerza la fuerza del jugador que chutara se usa para calcular el radio radio
	 * @return punto aleatorio
	 */
	public Point2D.Double crearPuntoAleatorio(Point2D.Double centro, int fuerza, double A, double B)
	{
		int radioMinimo = 20;
		Point2D.Double puntoAleatorio = new Point2D.Double();
		if(getDistanciaCritica(fuerza)+70 > centro.distance(-160, 0))
		{
			log.debug("EliminandoPorteria");
			
			double anguloPorteria = FutbolTools.calcAngulo(-160, 0, centro.getX(), centro.getY());
			double anguloA = 0;
			double anguloB = 0;
			
			if(A==0&&B==0){
				anguloA = FutbolTools.aA(FutbolTools.calcAngulo(centro, -160, 40), anguloPorteria);
				anguloB = FutbolTools.aA(FutbolTools.calcAngulo(centro, -160, -40), anguloPorteria);
			}else{
				anguloA = FutbolTools.aA(A, anguloPorteria);
				anguloB = FutbolTools.aA(B, anguloPorteria);
			}
			
			do{
				double distanciaDeChute = FutbolTools.distanciaMaximaDePelota(fuerza)+10;
				double angulo = anguloA+Math.random()*(anguloB-anguloA);
				double radio = radioMinimo+Math.random()*(distanciaDeChute-radioMinimo);
				puntoAleatorio = polarACartesiana(centro, radio, angulo);
			}while(estaDentroCampo(puntoAleatorio) != true);
		}
		else
		{
			
			do{
				double distanciaDeChute = FutbolTools.distanciaMaximaDePelota(fuerza);
				double angulo = Math.random()*2*Math.PI;
				double radio = 10+Math.random()*(distanciaDeChute-10);
				puntoAleatorio = polarACartesiana(centro, radio, angulo);
			}while(estaDentroCampo(puntoAleatorio) != true);
		}
       	return puntoAleatorio;
	}
	
	/** Controla si el punto esta dentro del campo o no
	 * 
	 * @param punto 
	 * @return true si esta dentro false si esta fuera
	 */
	public boolean estaDentroCampo(Point2D punto)
	{
		if (Math.abs(punto.getX()) < 160 )
		{	
			if(Math.abs(punto.getY()) < 120)
				return true;
			else
				return false;
		}	
		else
			return false;
	}
	
	public int tenemosPelota(){
		Juegaytoma yo = getMejoresInterceptores()[0];
		Juegaytoma el = getMejoresInterceptoresContrarios()[0];
		
		return (el.indicePelota - yo.indicePelota);
	}
	
	/**pase sense contraris en trajectoria,
	 * si retorna el numero de jugador d'origen no hi ha cap jugador a qui fer el pase
	 * 
	 * @param jugador jugador origen
	 * @param distMinPase distancia minima del jugador origen per fer el pase
	 * @return el numero de jugador a qui fer el pase
	 */
	public int paseSegur(Personalitat jugador,int distMinPase) 
	{
		int numJugs=0,
			nJug=jugador.numero;
		
		double 	distDeMi=0;
		
		Personalitat compis[] = getAlineacion();
		PelotaAnalista bola = getMiPelota();
		
		//log.debug("jugador "+numero+"-->calculant pase");
		int [][] jugadorYcualitatPase = new int [11][2];
		for(int i=0;i<11;i++)
		{
			distDeMi = compis[i].distance(jugador.x,jugador.y);

			// buscar millor compay x passar la pilota 
			// si el jugador esta mol aprop no passarli!
			// millor si el jugador esta en una x major q la meva
			
			if(i!=jugador.numero &&  (distDeMi > distMinPase && FutbolTools.distanciaMaximaDePelota(jugador.fuerza) >= distDeMi ))
			{

				if(contrariEnTrajectoria(jugador, bola.getCopia(),i) >= 0 )
				{
					jugadorYcualitatPase[numJugs][0] = i;
					jugadorYcualitatPase[numJugs][1] = contrariEnTrajectoria(jugador,bola,i);
					numJugs++;
				}
			}
		}
		int maxFactor=0;
		
		double jugadorYx[][];
		for(int i=0;i<numJugs;i++)
		{
			if(jugadorYcualitatPase[i][1] > maxFactor && getAlineacion()[jugadorYcualitatPase[i][0]].x > jugador.x)
			{
				maxFactor = jugadorYcualitatPase[i][1];
				nJug = i;
			}
		}
	
		double maxX = -150;
		if(nJug== jugador.numero)
		{
			for(int i=0;i<numJugs;i++)
			{
				if(jugadorYcualitatPase[i][1] > 0 && getAlineacion()[jugadorYcualitatPase[i][0]].x >maxX)
				{
					maxFactor = jugadorYcualitatPase[i][1];
					maxX = getAlineacion()[jugadorYcualitatPase[i][0]].x;
					nJug = i;
				}
			}
		}
		return nJug;
	}
	public int paseSegur(Personalitat jugador,int distMinPase,boolean soloPalante) 
	{
		int numJugs=0,
			nJug=jugador.numero;
		
		double 	distDeMi=0;
		
		Personalitat compis[] = getAlineacion();
		PelotaAnalista bola = getMiPelota();
		
		//log.debug("jugador "+numero+"-->calculant pase");
		int [][] jugadorYcualitatPase = new int [11][2];
		for(int i=0;i<11;i++)
		{
			distDeMi = compis[i].distance(jugador.x,jugador.y);

			// buscar millor compay x passar la pilota 
			// si el jugador esta mol aprop no passarli!
			// millor si el jugador esta en una x major q la meva
			
			if(i!=jugador.numero &&  distDeMi > distMinPase &&
				FutbolTools.distanciaMaximaDePelota(jugador.fuerza) -5 >= distDeMi )
			{

				double puntPase[] = FutbolTools.pasePreciso(jugador, bola.getCopia(), compis[i].numero);
				
				if(contrariEnTrajectoria(jugador,bola,i) >= 0)
				{
					jugadorYcualitatPase[i][0] = i;
					jugadorYcualitatPase[i][1] = contrariEnTrajectoria(jugador,bola,i);
					numJugs++;
				}
			}
		}
		int maxFactor=0;
		
		
		for(int i=0;i<numJugs;i++)
		{
			if(jugadorYcualitatPase[i][1] > maxFactor && getAlineacion()[jugadorYcualitatPase[i][0]].x > jugador.x)
			{
				maxFactor = jugadorYcualitatPase[i][1];
				nJug = i;
			}
		}
		double maxX = -150;
		if(nJug== jugador.numero && !soloPalante)
		{
			for(int i=0;i<numJugs;i++)
			{
				if(jugadorYcualitatPase[i][1] > 0 && getAlineacion()[jugadorYcualitatPase[i][0]].x >maxX)
				{
					//maxFactor = jugadorYcualitatPase[i][1];
					maxX = getAlineacion()[jugadorYcualitatPase[i][0]].x;
					nJug = i;
				}
			}
		}
		return nJug;
	}
	
	/**pase al jugador que tŽ mŽs lluny als jugadors contraris, tŽ prioritat si esta
	 * mes abansat que tu (es compta que s'hi arribi segons la forsa del jugador)
	 * 
	 * @param jugador jugador origen
	 * @return numero de jugador per fer el pase o el d'origen si no n'hi ha cap de bo
	 */
	public int paseAdesmarcat(Personalitat jugador)
	{
		int nContrari,
			nJug=jugador.numero;
		
		double 	distContrari=0, 
				distDeMi=0,
				rel=0, 
				m_rel=0;
		
		Personalitat compis[] = this.getAlineacion();//this.getUltimaSJ().getMisJugadores();
		
		//log.debug("jugador "+numero+"-->calculant pase");
		
		for(int i=0;i<11;i++) 
		{
			nContrari = this.getUltimaSJ().getContrarioMasCerca(i);
			distContrari = compis[i].distance(this.getUltimaSJ().getContrario()[nContrari]);
			distDeMi = compis[i].distance(jugador.x,jugador.y);
		
			rel= distContrari;// / distDeMi;
			// modificar pq tingui en compte nomes els jugadors als q arribes
			// pasar de la distancia a tu
			if(i!=jugador.numero && rel > m_rel && 
				FutbolTools.distanciaMaximaDePelota(jugador.fuerza) -5 >= distDeMi &&
				compis[i].x > jugador.x)
			{
				nJug = i;
				m_rel = rel;
			}
		}
		// si no he trobat un compi x pase	aban�at paso enrere
		if(nJug == jugador.numero) 
		{
			for(int i=0;i<11;i++) 
			{
				nContrari = this.getUltimaSJ().getContrarioMasCerca(i);
				distContrari = compis[i].distance(this.getUltimaSJ().getContrario()[nContrari]);
				distDeMi = compis[i].distance(jugador.x,jugador.y);
			
				rel= distContrari;// / distDeMi;
				// modificar pq tingui en compte nomes els jugadors als q arribes
				// pasar de la distancia a tu
				if(i!=jugador.numero && rel > m_rel && 
					FutbolTools.distanciaMaximaDePelota(jugador.fuerza) -5 >= distDeMi)
				{
					nJug = i;
					m_rel = rel;
				}
			}
		}
		return nJug;
	}
	
	/**El mateix que contrariEnTrajectoria pero orientada a xuts a porta enlloc de a pases*/
	public boolean contrariEnTrajectoriaPorteria(Personalitat jugador,PelotaAnalista pelotaOrigen)
	{
		
		ArrayList <PelotaAnalista> trayecto = new ArrayList<PelotaAnalista>();
		
		Point2D p = this.canyonazo(miPelota, 160, 0);
		PelotaAnalista pilotaHipotetica = FutbolTools.createPelotaSegunDestino(jugador, jugador.fuerza, pelotaOrigen, p.getX(), p.getY());
		
		// trayecto son tots els punts on passara la pilota
		FutbolTools.calculTrajectoria(pilotaHipotetica,trayecto);
		
		// comprobo si algun contrari esta en la trajectoria
		for(int i=0;i<11;i++)
		{
			Point contrari = this.getUltimaSJ().getContrario()[i];
			for(int j=0;j<trayecto.size();j++)
			{
				if (contrari.distance(trayecto.get(j)) <= this.getVelocidadJugadorContrario(i)*(j+1))
				{
					//System.err.println("contrari en trajectoria!");
					return true;
				}
			}
		}
		return false;	
	}
	
	public Point2D.Double getPosicionDeDesmarque(int numeroJugador, int velocidad)
	{
		log.debug("DESMARCADOR - desmarcandome");
		PelotaAnalista 				pelotaInterceptar;
		Juegaytoma[] 		interceptores;
		Point2D.Double 				mejorInterceptor;
		Personalitat					pers 					= getAlineacion()[numeroJugador];
		

		
		interceptores		= getMejoresInterceptores();
		mejorInterceptor 	= getAlineacion()[interceptores[0].indiceJugador];
		
		//pelotaInterceptar	= getPelotaAInterceptarTemporal(getTrayectoria(), mejorInterceptor, getAlineacion()[interceptores[0].indiceJugador].velocidad);
		
		double[] posicion = new double[2];
		Point2D.Double positionDesparque = null;
		Point2D.Double posicionObjetivo = mejorInterceptor;
		
		
		posicion = 	this.irHaciaConEvasion(	pers,
				this.getRutasLibres(pers, pers.distance(posicionObjetivo), posicionObjetivo),
				posicionObjetivo);
		
		if(posicion!=null){
		     positionDesparque = new Point2D.Double(posicion[0],posicion[1]);
		}else{
			positionDesparque = new Point2D.Double(pers.xInicial,pers.yInicial);
		}
		
		return positionDesparque;
	}
}
